package src.accenture.com.backing;

import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.myfaces.trinidad.context.RequestContext;
import src.accenture.com.Common.CommonUtil;
import src.accenture.com.Common.GlobalConstants;
import src.accenture.com.entity.MblEmployee;
import src.accenture.com.entity.MblHolidaytype;
import src.accenture.com.entity.MblRegistration;
import src.accenture.com.session.SessionEJB;
import src.accenture.com.view.Holiday;
import src.accenture.com.view.HolidaylistView;
import src.accenture.com.view.ParamObj;

public class Holidaylist {

    private MblEmployee userLogin;
    private MblHolidaytype holidayType;
    private Double holidayNum;
    private boolean rendered;
    private Context context = null;
    private SessionEJB sessionBean;
    private HolidaylistView holidaylistView;
    protected RequestContext currentRequestContext;

    public Holidaylist() throws NamingException {
        context = new InitialContext();
        sessionBean = (SessionEJB)context.lookup("HolidaySessionEJB#src.accenture.com.session.SessionEJB");
        holidaylistView = this.getEntity();
        this.userLogin = CommonUtil.getMblEmployeeFromSession();
        currentRequestContext = RequestContext.getCurrentInstance();

        if (!FacesContext.getCurrentInstance().isPostback()) {
            this.setDataCombobox();
            this.setApprovalStatus(0);
            this.setDataForTable(this.holidaylistView.getTypeHolidayId(), this.holidaylistView.getApprovalStatus());
        }

    }

    public void searchAction() {

        System.out.println("You clicked:" + this.holidaylistView.getTypeHolidayId());
        this.holidaylistView.setTypeHolidayName(this.holidaylistView.getTypeHolidayName());
        this.setDataForTable(this.holidaylistView.getTypeHolidayId(), this.holidaylistView.getApprovalStatus());
    }

    public void statusChangeListener(ValueChangeEvent valueChangeEvent) {
        if (!valueChangeEvent.getNewValue().equals(valueChangeEvent.getOldValue())) {
            this.holidaylistView.setApprovalStatus((Integer)valueChangeEvent.getNewValue());
            this.setDataForTable(this.holidaylistView.getTypeHolidayId(), (Integer)valueChangeEvent.getNewValue());
        }
    }

    private void setDataForTable(String typeId, int status) {
        List<MblRegistration> registrationList = new ArrayList<MblRegistration>();
        registrationList = sessionBean.getHoliday(this.userLogin.getEmpId(), typeId, status);
        this.setHolidayType(sessionBean.getHolidaytype(typeId));

        Holiday holiday = null;
        List<Holiday> holidayList = new ArrayList<Holiday>();
        Format formatter = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_SHORT_DATE);

        for (MblRegistration registration : registrationList) {
            holiday =
                    new Holiday(registration.getReason(), registration.getFromtime(), formatter.format(registration.getFromdate()),
                                registration.getTotime(), formatter.format(registration.getTodate()));
            holidayList.add(holiday);
        }

        this.holidaylistView.setHolidayList(holidayList);

        if (holidayList.size() != 0) {
            this.holidaylistView.setMessage(null);
            this.setRendered(true);

            if (status == 1) {
                //approved status
                double usedTime = getTotalHolidayTimeByType(registrationList);
                this.setDataGraphByHolidayType(usedTime);

            } else {
                this.clearDataGraphByHolidayType();
            }

        } else {
            this.holidaylistView.setMessage(GlobalConstants.CONST_MESSAGE_NO_DATA);
            this.setRendered(false);
            this.clearDataGraphByHolidayType();
        }
    }

    private void setDataCombobox() {
        List<MblHolidaytype> holidaytypeList = new ArrayList<MblHolidaytype>();
        holidaytypeList = sessionBean.getMblHolidaytypeFindAll();
        List<SelectItem> listSelectItem = new ArrayList<SelectItem>();
        SelectItem selectItemDefault = null;

        for (MblHolidaytype holidaytype : holidaytypeList) {
            selectItemDefault = new SelectItem();
            selectItemDefault.setValue(holidaytype.getTypeId());
            selectItemDefault.setLabel(holidaytype.getDescribe());
            listSelectItem.add(selectItemDefault);
        }
        this.holidaylistView.setTypeHolidayList(listSelectItem);
        this.holidaylistView.setTypeHolidayId(this.holidaylistView.getTypeHolidayList().get(0).getValue().toString());
    }

    private void setApprovalStatus(int b) {
        this.holidaylistView.setApprovalStatus(b);
    }

    /**
     * Gets entity.
     * @return ClientChooseEntity
     */
    public HolidaylistView getEntity() {
        return (HolidaylistView)CommonUtil.getManagedBeanValue("view_holidaylistview");
    }

    private void setDataGraphByHolidayType(double usedTime) {

        double totalTime = 0D;

        String roleName = this.getUserLogin().getMblRole().getRoleName();
        if (roleName.equals(GlobalConstants.CONST_LEADER_ROLE) ||
            roleName.equals(GlobalConstants.CONST_MANAGER_ROLE)) {

            totalTime = this.getHolidayType().getManagerHolidaynum();

            System.out.println("Manager " + this.getHolidayType().getDescribe() + " Num:" +
                               this.getHolidayType().getManagerHolidaynum());
        } else {

            totalTime = this.getHolidayType().getEmpHolidaynum();

            System.out.println("Employee " + this.getHolidayType().getDescribe() + " Num:" +
                               this.getHolidayType().getEmpHolidaynum());
        }

        if (totalTime >= usedTime) {
            double freeTime = totalTime - usedTime;
            this.holidaylistView.getTabularData().clear();
            this.holidaylistView.getTabularData().add(new Object[] { "Time", "Used : " + usedTime + "h", usedTime });
            this.holidaylistView.getTabularData().add(new Object[] { "Time", "Free : " + freeTime + "h", freeTime });
        } else {
            this.holidaylistView.getTabularData().add(new Object[] { "Time", "Used : " + usedTime + "h", usedTime });
        }

        this.holidaylistView.setApproved(true);
    }

    private void clearDataGraphByHolidayType() {
        this.holidaylistView.getTabularData().clear();
        this.holidaylistView.setApproved(false);
    }

    public void setRendered(boolean rendered) {
        this.rendered = rendered;
    }

    public boolean isRendered() {
        return rendered;
    }


    public Object getParam(String paramKey) {
        Object result = currentRequestContext.getPageFlowScope().get(paramKey);
        currentRequestContext.getPageFlowScope().remove(paramKey);
        return result;
    }

    public void putParam(String paramKey, Object paramValue) {
        currentRequestContext.getPageFlowScope().put(paramKey, paramValue);
    }

    public String toDetailPage() {

        ParamObj obj = new ParamObj();
        obj.setHolidayTypeId(this.holidaylistView.getTypeHolidayId());
        obj.setHolidayTypeName(this.sessionBean.getHolidayTypeNameById(this.holidaylistView.getTypeHolidayId()));
        obj.setFromTime(this.holidaylistView.getSelectedHoliday().getFromTime());
        obj.setFromDate(this.holidaylistView.getSelectedHoliday().getFromDate());
        obj.setToTime(this.holidaylistView.getSelectedHoliday().getToTime());
        obj.setToDate(this.holidaylistView.getSelectedHoliday().getToDate());
        obj.setReason(this.holidaylistView.getSelectedHoliday().getReason());
        this.putParam("Param", obj);
        return "detail";
    }

    public String toRegistPage() {

        ParamObj obj = new ParamObj();
        obj.setHolidayTypeId(this.holidaylistView.getTypeHolidayId());
        obj.setHolidayTypeName(this.sessionBean.getHolidayTypeNameById(this.holidaylistView.getTypeHolidayId()));
        obj.setFromTime(null);
        obj.setFromDate(null);
        obj.setToTime(null);
        obj.setToDate(null);
        obj.setReason(null);
        this.putParam("Param", obj);
        return "detail";
    }

    private double getTotalHolidayTimeByType(List<MblRegistration> registrationList) {

        double totalTime = 0D;
        if (null == registrationList || registrationList.size() == 0) {
            return totalTime;
        }

        Format formatSdt = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_SHORT_DATE);
        String from = null;
        String to = null;

        for (MblRegistration obj : registrationList) {
            from = obj.getFromtime().trim().concat(" ").concat(formatSdt.format(obj.getFromdate()));
            to = obj.getTotime().trim().concat(" ").concat(formatSdt.format(obj.getTodate()));
            totalTime += getTimeWorkTotal(from, to);
        }
        return totalTime;
    }

    private double getTimeWorkTotal(String from, String to) {
        double workTime = 0D;
        boolean isfirstday = true;
        Date fromDate = new Date();
        Date toDate = new Date();
        Date fromSDate = new Date();
        Date toSDate = new Date();
        Format formatDt = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_DATE);
        Format formatSdt = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_SHORT_DATE);
        
        try {
            fromDate = (Date)formatDt.parseObject(from);
            toDate = (Date)formatDt.parseObject(to);
            fromSDate = (Date)formatSdt.parseObject(from.substring(5, 16));
            toSDate = (Date)formatSdt.parseObject(to.substring(5, 16));

            while (fromDate.compareTo(toDate) <= 0) {
                if (!checkWeekend(fromDate)) {
                    if (fromSDate.compareTo(toSDate) == 0) {
                        workTime += this.getTimeEndWorkAday(toDate);
                    } else {
                        workTime += this.getTimeWorkAday(fromDate);
                    }
                }
                //next from date
                fromDate = this.seekDateByDay(fromDate, 1);
                fromSDate = this.seekDateByDay(fromSDate, 1);
            }
        } catch (ParseException pe) {
            System.out.println(pe.getMessage());
        }
        return workTime;
    }

    private double getTimeWorkAday(Date date) {
        //format of input date must be CONST_FORMAT_DATE (HH:mm dd/MM/yyyy)
        double t = 0D;
        if (null == date) {
            return t;
        }
        Date myDate = new Date();
        Date startDay = new Date();
        Date startRelax = new Date();
        Date endRelax = new Date();
        Date endDay = new Date();
        Format formatDt = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_DATE);
        StringBuilder strDate = new StringBuilder(formatDt.format(date));
        String inputDate = strDate.toString();

        try {
            myDate = (Date)formatDt.parseObject(inputDate);
            startDay =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_START_WORKTIME.concat(inputDate.substring(5, 16)));
            startRelax =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_AFTERNOON_START_WORKTIME.concat(inputDate.substring(5,
                                                                                                                         16)));
            endRelax =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_AFTERNOON_END_WORKTIME.concat(inputDate.substring(5,
                                                                                                                       16)));
            endDay = (Date)formatDt.parseObject(GlobalConstants.CONST_END_WORKTIME.concat(inputDate.substring(5, 16)));

            if (myDate.before(startDay)) {
                myDate = startDay;
            }
            if (myDate.after(endDay)) {
                myDate = endDay;
            }
            if (myDate.compareTo(startRelax) < 0) {
                t =
  ((double)(endDay.getTime() - myDate.getTime()) / (1000 * 3600)) - GlobalConstants.CONST_AFTERNOON_RELAX;

            } else if (myDate.compareTo(startRelax) >= 0 & myDate.compareTo(endRelax) <= 0) {

                t = ((double)(endDay.getTime() - endRelax.getTime()) / (1000 * 3600));
            } else if (myDate.compareTo(endRelax) > 0) {

                t = ((double)(endDay.getTime() - myDate.getTime()) / (1000 * 3600));
            }

        } catch (ParseException pe) {
            System.out.println(pe.getMessage());
        }
        return t;
    }

    private double getTimeEndWorkAday(Date date) {
        //format of input date must be CONST_FORMAT_DATE (HH:mm dd/MM/yyyy)
        double t = 0D;
        if (null == date) {
            return t;
        }
        Date myDate = new Date();
        Date startDay = new Date();
        Date startRelax = new Date();
        Date endRelax = new Date();
        Date endDay = new Date();
        Format formatDt = new SimpleDateFormat(GlobalConstants.CONST_FORMAT_DATE);
        StringBuilder strDate = new StringBuilder(formatDt.format(date));
        String inputDate = strDate.toString();
        try {
            myDate = (Date)formatDt.parseObject(inputDate);
            startDay =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_START_WORKTIME.concat(inputDate.substring(5, 16)));
            startRelax =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_AFTERNOON_START_WORKTIME.concat(inputDate.substring(5,
                                                                                                                         16)));
            endRelax =
                    (Date)formatDt.parseObject(GlobalConstants.CONST_AFTERNOON_END_WORKTIME.concat(inputDate.substring(5,
                                                                                                                       16)));
            endDay = (Date)formatDt.parseObject(GlobalConstants.CONST_END_WORKTIME.concat(inputDate.substring(5, 16)));

            if (myDate.before(startDay)) {
                myDate = startDay;
            }
            if (myDate.after(endDay)) {
                myDate = endDay;
            }

            if (myDate.compareTo(endRelax) > 0) {
                t =
  ((double)(myDate.getTime() - startDay.getTime()) / (1000 * 3600)) - GlobalConstants.CONST_AFTERNOON_RELAX;

            } else if (myDate.compareTo(startRelax) >= 0 & myDate.compareTo(endRelax) <= 0) {

                t = ((double)(startRelax.getTime() - startDay.getTime()) / (1000 * 3600));
            } else if (myDate.compareTo(startRelax) < 0) {

                t = ((double)(myDate.getTime() - startDay.getTime()) / (1000 * 3600));
            }

        } catch (ParseException pe) {
            System.out.println(pe.getMessage());
        }
        return t;
    }

    private boolean checkWeekend(Date inputDate) {

        boolean isweekend = false;
        Calendar c = Calendar.getInstance();
        c.setTime(inputDate);

        if ((c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) || (c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)) {
            isweekend = true;
        }
        return isweekend;
    }

    private Date seekDateByDay(Date date, int daySeek) {
        if (date == null) {
            return null;
        }

        Calendar seekedDate = Calendar.getInstance();
        seekedDate.setTime(date);
        //set start time of the next day is 8h am
        seekedDate.set(Calendar.HOUR_OF_DAY, 8);
        seekedDate.set(Calendar.DAY_OF_MONTH, seekedDate.get(Calendar.DAY_OF_MONTH) + daySeek);

        return seekedDate.getTime();
    }

    public void setUserLogin(MblEmployee userLogin) {
        this.userLogin = userLogin;
    }

    public MblEmployee getUserLogin() {
        return userLogin;
    }

    public void setHolidayNum(Double holidayNum) {
        this.holidayNum = holidayNum;
    }

    public Double getHolidayNum() {
        return holidayNum;
    }

    public void setHolidayType(MblHolidaytype holidayType) {
        this.holidayType = holidayType;
    }

    public MblHolidaytype getHolidayType() {
        return holidayType;
    }
}
